package org.xx.armory.spring5.data;

import org.springframework.data.domain.Page;

import java.util.ArrayList;
import java.util.List;

/**
 * 页面链接创建工具。
 */
public class PageLinkCreator {
    /**
     * 构造一组分页链接。
     *
     * @param total
     *         总记录数。
     * @param pageSize
     *         每页记录数。
     * @param maxPages
     *         最多显示的页码数（不包含上一页和下一页链接）。
     * @param startRowIndex
     *         当前页的第一条记录的序号（从0开始）。
     * @return 生成的所有分页链接。
     * @throws IllegalArgumentException
     *         如果参数 {@code total} 小于 {@code 0} ，或者 {@code pageSize} 小于 {@code 1} ，或者参数 {@code maxPages} 小于 {@code 3}
     *         ，或者 {@code maxPages} 不是奇数，或者 {@code startRowIndex} 小于 {@code 0} 。
     */
    public List<PageLink> execute(
            int total,
            int pageSize,
            int maxPages,
            int startRowIndex
    ) {
        if (total < 0) {
            throw new IllegalArgumentException("total cannot less than 0");
        }
        if (pageSize < 1) {
            throw new IllegalArgumentException("pageSize cannot less than 1");
        }
        if (maxPages < 3) {
            throw new IllegalArgumentException("maxPages cannot less than 5");
        }
        if (maxPages % 2 == 0) {
            throw new IllegalArgumentException("maxPages cannot be even");
        }
        if (startRowIndex < 0) {
            throw new IllegalArgumentException("startRowIndex cannot less than 0");
        }
        if (startRowIndex > total) {
            startRowIndex = total;
        }
        startRowIndex -= startRowIndex % pageSize;

        final List<PageLink> ret = new ArrayList<>(maxPages + 2);

        // 计算页码参数。
        final int curPage = startRowIndex / pageSize + 1;
        int totalPage = total / pageSize;
        if (total % pageSize != 0) totalPage += 1;
        int minPage = curPage - maxPages / 2;
        if (minPage < 1) minPage = 1;
        int maxPage = minPage + maxPages - 1;
        if (maxPage > totalPage) maxPage = totalPage;

        // 总页码大于1的时候才需要分页。
        if (totalPage > 1) {
            // 如果当前页不是第一页则添加上一页链接。
            if (curPage != 1) {
                ret.add(new PageLink("<", startRowIndex - pageSize, pageSize, startRowIndex));
            }

            // 第一页。
            ret.add(new PageLink("1", 0, pageSize, startRowIndex));

            // 第一页与minPage之间的省略。
            if (minPage > 2) {
                ret.add(null);
            }

            // 从minPage到maxPage。
            for (int n = minPage; n <= maxPage; ++n) {
                if (n == 1 || n == totalPage) continue;
                ret.add(new PageLink(String.valueOf(n), (n - 1) * pageSize, pageSize, startRowIndex));
            }

            // maxPage 到最后一页的省略。
            if (maxPage < totalPage - 1) {
                ret.add(null);
            }

            // 最后一页。
            ret.add(new PageLink(String.valueOf(totalPage), (totalPage - 1) * pageSize, pageSize, startRowIndex));

            // 如果当前页不是最后一页则添加下一页链接。
            if (curPage != totalPage) {
                ret.add(new PageLink(">", startRowIndex + pageSize, pageSize, startRowIndex));
            }
        }

        return ret;
    }

    public List<PageLink> execute(
            Page<?> page,
            int maxPages
    ) {
        return execute((int) page.getTotalElements(), page.getSize(), maxPages, page.getNumber() * page.getSize());
    }
}
